﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.Extensions.DependencyInjection;

namespace PerryPractice
{
    public static class PerryExtensions
    {
        public static IServiceCollection RegisterDependencyInjection(this IServiceCollection services, Assembly assembly)
        {
            var types = assembly.GetTypes();
            foreach (var type in types)
            {
                var attrs = type.GetCustomAttributes<LifetimeAttribute>().Where(t=> !t.GetType().IsAssignableFrom(typeof(LifetimeAttribute)));
                if (attrs.Count()>0)
                {
                    services.RegisterService(type);
                }
                else
                {
                    var interfaces = type.GetInterfaces().Where(x => typeof(ILifetime).IsAssignableFrom(x) && !x.IsAssignableFrom(typeof(ILifetime)));
                    if (interfaces.Count()>0)
                    {
                        services.RegisterService(type);
                    }
                }
            }
            return services;
        }

        public static IServiceCollection RegisterService(this IServiceCollection services, Type tImplement)
        { 
            Type tRegister = GetRegisterType(tImplement) ??
                throw new Exception("register failed, no suitable interface");
      
            if (tRegister.IsAssignableFrom(tImplement))
            {
                var lifetime = GetLifetime(tImplement);
                var serviceDiscriptor = ServiceDescriptor.Describe(tRegister, tImplement, lifetime);
                services.Add(serviceDiscriptor);
            }
            return services;
        }

        private static Type GetRegisterType(Type t)
        {
            var interfaces = t.GetInterfaces();
            var registerType = interfaces.FirstOrDefault(i => i.Name.StartsWith("I") && i.Name.EndsWith(t.Name));
            if (registerType is not null)
            {
                return registerType;
            }
            return null;
        }

        /// <summary>
        /// 获取生命周期
        /// </summary>
        private static ServiceLifetime GetLifetime(Type tImplement)
        {
            // 特性
            var lifetimeAttribute = tImplement.GetCustomAttribute<LifetimeAttribute>();
            if (lifetimeAttribute is not null)
            {
                return lifetimeAttribute switch
                {
                    TransientAttribute => ServiceLifetime.Transient,
                    ScopedAttribute => ServiceLifetime.Scoped,
                    SingletonAttribute => ServiceLifetime.Singleton,
                    _ => throw new ArgumentException(tImplement.Name, "unsupported dependency attribute")
                };
            }

            // 接口
            var interfaces = tImplement.GetInterfaces();

            var lifetimeInterface = interfaces.FirstOrDefault(i => typeof(ILifetime).IsAssignableFrom(i) && i != typeof(ILifetime));
            if (lifetimeInterface is not null)
            {
                if (lifetimeInterface.Equals(typeof(ITransient)))
                    return ServiceLifetime.Transient;
                else if (lifetimeInterface.Equals(typeof(IScoped)))
                    return ServiceLifetime.Scoped;
                else if (lifetimeInterface.Equals(typeof(ISingleton)))
                    return ServiceLifetime.Singleton;
                else
                    throw new ArgumentException(tImplement.Name, "unsupported dependency interface");
            }
            throw new ArgumentException(tImplement.Name);
        }
    }
}
